<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // 获取随机数 => 异步版,返回Promise实例(pending) 指定时间之后可以变为fulfilled/rejected
    function getNumAsync(num, delay = 0, isFulfilled = true) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                isFulfilled ? resolve(num) : reject(num);
            }, delay);
        })
    }

    // 如果多个异步操作之间不相互依赖,同时启动多个异步操作,按顺序返回结果
    // var p1 = getNumAsync(1, 2000); // 2s
    // var p2 = getNumAsync(2, 1000); // 1s
    // var p3 = getNumAsync(3, 3000); // 3s

    // var list = []
    // p1.then((res) => {
    //     console.log("fulfilled", res);
    //     return p2;
    // }).then((res) => {
    //     console.log("fulfilled", res);
    //     return p3; // 3s
    // }).then(res => {
    //     console.log("fulfilled", res);
    // }).catch(err => {
    //     console.log("rejected", err);
    // })

    // 上述代码,同时启动三个异步操作(全部都有结果,最多耗时3s) =>  p1状态改变需要2s => 执行then方法,此时p2状态已经改变, 继续向后调用then()方法, 再等待1s,p3的状态也会改变  => 总共耗3s
    // 缺点: 虽然多个异步操作同时启动,但是还需要通过链式操作,执行数据返回顺序  => 麻烦


    /* 
        构造函数Promise的方法  => 构造函数Promise自己用
        Promise.all(list) 方法用于将多个 Promise 实例，包装成一个新的 Promise 实例。
        var p = Promise.all([p1,p2,p3]);

        Promise.all()方法接受一个数组作为参数，p1、p2、p3都是 Promise 实例，如果不是，就会先调用下面讲到的Promise.resolve方法，将参数转为 Promise 实例，再进一步处理

        p的状态由p1、p2、p3决定，分成两种情况。

        （1）只有p1、p2、p3的状态都变成fulfilled，p的状态才会变成fulfilled，此时p1、p2、p3的存储的数据组成一个数组，传递给p(存储到新的Promise实例中)。

        （2）只要p1、p2、p3之中有一个被rejected，p的状态就变成rejected，此时第一个被reject的实例的返回值，会传递给p的回调函数。

        // 技巧: 全都成功才成功,有一个失败就失败  (全都成功,总的事件按最慢的来)


    
     */

    // 如果多个异步操作之间不相互依赖,同时启动多个异步操作,按顺序返回结果
    // var p1 = getNumAsync(1, 2000); // 2s
    // var p2 = getNumAsync(2, 1000); // 1s
    // var p3 = getNumAsync(3, 3000); // 3s

    // var p = Promise.all([p1, p2, p3])
    // console.log("新的Promise实例p", p);

    // p.then(list => {
    //     console.log("全都成功", list);
    // }).catch(err => {
    //     console.log("任意一个失败", err);
    // })

    // for (let i = 0; i < 6; i++) {
    //     setTimeout(() => {
    //         console.log(i); // 6
    //     }, 1000)
    // }



    // 模拟封装
    Promise.myAll = function (list) { // [p1(2s), p2(1s), p3(3s)]
        return new Promise(function (resolve, reject) { // 新的Promise实例
            var count = 0;
            var arr = [];
            for (let i = 0; i < list.length; i++) {  // 遍历数组 
                let item = Promise.resolve(list[i]); // 每一个Promise实例
                item.then(res => {  // 因为 p1,p2,p3是异步操作  => then/catch对应的回调函数执行时也是异步(问题: i 是跳出循环的值 i = 3 )
                    count++;  // 每次成功计数

                    // arr.push(res);  // 直接加 => 先执行的先push
                    arr[i] = res;  // 对应下标赋值

                    if (count == list.length) {  // 全都成功,才成功
                        resolve(arr);
                    }

                }).catch(err => {
                    reject(err);  // 有一个失败就失败
                })
            }

        })
    }


    var p1 = getNumAsync(1, 2000); // 2s
    var p2 = getNumAsync(2, 1000); // 1s
    var p3 = getNumAsync(3, 3000); // 3s

    var p = Promise.myAll([p1, p2, p3, 4])
    console.log("新的Promise实例p", p);

    p.then(list => {
        console.log("全都成功", list);
    }).catch(err => {
        console.log("任意一个失败", err);
    })














</script>

</html>